﻿/*
ParallelPlatform Project - A web platform to distribute and share knowledge
Online Editor - An online tool to create and play animations
Copyright (C) 2011 Daniel Guerrero Martínez & Sergio Rodríguez Lumley

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package Classes{

	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.ui.Mouse;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.AntiAliasType;
	import flash.text.TextFieldType;
	import flash.text.TextFieldAutoSize;
	
	public class CanvasBlurHandler extends CanvasDefaultHandler {
		private var backSelectionRect:	MovieClip;
		private var editingLines:		MovieClip;
		private var blurCursor:			CursorBlur;
		private var selectionBackup:	Array;
		private var editing:			Boolean;
		private var firstEditing:		Boolean;
		private var blurx:				Number;
		private var blury:				Number;
		private var tfield:				TextField;
		
		/**
		 Constructor
		*/
		function CanvasBlurHandler(c:CanvasCore){
			super(c);
			blurCursor 			= new CursorBlur();
			backSelectionRect	= new MovieClip();
			editingLines		= new MovieClip();
			editing				= false;
			firstEditing		= false;
			tfield				= new TextField();
			blurCursor.x		= -1000;
			
			// TextField data
			var tformat:TextFormat 	= new TextFormat();
			tformat.align 	= "left";
			tformat.font	= (new Font_Sans()).fontName;
			tformat.size	= 16; // Default size for Text
			tformat.bold	= true;
			tformat.color	= 0xFFAA00; // Default color for Text
			
			tfield.type				= TextFieldType.DYNAMIC;
			tfield.multiline		= false;
			tfield.wordWrap			= false;
			tfield.selectable		= false;
			tfield.embedFonts		= true;
			tfield.antiAliasType 	= AntiAliasType.ADVANCED;
			tfield.autoSize 		= TextFieldAutoSize.LEFT;
			tfield.defaultTextFormat = tformat; // Assign the text format
		}
		
		override public function activate(param = null):void{
			if(!activated){
				activated = true;
				core.showBlockPanel(false);
				if(core.getSelectedShapes().length > 0){
					core.getBackPanel().addChild(backSelectionRect);
					refreshBackSelectionRect();
				}
				core.addChild(blurCursor);
				backSelectionRect.addEventListener(MouseEvent.MOUSE_DOWN, backRectDown);
				backSelectionRect.addEventListener(MouseEvent.MOUSE_OVER, showBlurCursor);
				backSelectionRect.addEventListener(MouseEvent.MOUSE_OUT, hideBlurCursor);
			}
		}
		
		override public function deactivate():void{
			if(activated){
				activated = false;
				if(core.getSelectedShapes().length > 0){
					core.getBackPanel().removeChild(backSelectionRect);
				}
				core.removeChild(blurCursor);
				backSelectionRect.removeEventListener(MouseEvent.MOUSE_DOWN, backRectDown);
				backSelectionRect.removeEventListener(MouseEvent.MOUSE_OVER, showBlurCursor);
				backSelectionRect.removeEventListener(MouseEvent.MOUSE_OUT, hideBlurCursor);
			}
		}
		
		override public function mouseUp(evt:MouseEvent):void{
			if(editing && firstEditing){
				saveSelectedShapesBlur(evt);
			}
			editing 		= false;
			firstEditing 	= false;
		}
		
		override public function mouseMove(evt:MouseEvent):void{
			if(editing){
				selectedShapesBlur(evt);
			}
		}
		
		override public function clickShape(evt:MouseEvent, obj:ShapeObject, type:int):void{
			if(type == ShapeObject.SINGLECLICK){
				if(evt.shiftKey){ // If we are pressing shift, we want to unselect it
					if(core.getSelectedShapes().indexOf(obj) < 0){
						this.addShapeToSelection(obj);
					}else{
						this.removeShapeFromSelection(obj);
					}
				}else{
					this.removeSelections();
					this.addShapeToSelection(obj);
				}
			}
		}
		
		override public function clickBack(evt:MouseEvent):void{
			this.removeSelections();
		}
		
		// -------------- PRIVATE FUNCTIONS ----------------//
		
		/**
		  Adds obj to selected shapes
		  @param obj ShapeObject to add
		*/
		private function addShapeToSelection(obj:ShapeObject):void{
			core.addShapeToSelection(obj);
			if(core.getSelectedShapes().length == 1){
				core.getBackPanel().addChild(backSelectionRect);
			}
			refreshBackSelectionRect();
		}
		
		/**
		  Mouse down in backRect
		*/
		private function backRectDown(evt:MouseEvent):void{
			editing = true;
			blurx	= 0;
			blury	= 0;
			
			// We save all shape's scaling
			selectionBackup = new Array(core.getSelectedShapes().length+1);
			
			// We save in the first position the point as reference
			selectionBackup[0] = new Point(core.getMainSelectionRect().x + core.getMainSelectionRect().width/2,
											core.getMainSelectionRect().y + core.getMainSelectionRect().height/2); 
			for(var i:uint = 0; i<core.getSelectedShapes().length; ++i){
				selectionBackup[i+1] = core.getSelectedShapes()[i].getBlur();
			}
		}
		
		/**
		  Hides the original cursor and shows the rotate one
		*/
		private function hideBlurCursor(evt:MouseEvent):void{
			Mouse.show();
			blurCursor.stopDrag();
			blurCursor.x = -1000;
		}
		
		/**
		  Removes all selected shapes
		*/
		private function removeSelections():void{
			if(core.getSelectedShapes().length > 0){
				core.getBackPanel().removeChild(backSelectionRect);
			}
			core.removeSelections();
		}
		
		/**
		  Removes obj from selected shapes
		  @param obj ShapeObject to remove
		*/
		private function removeShapeFromSelection(obj:ShapeObject):void{
			core.removeShapeFromSelection(obj);
			if(core.getSelectedShapes().length <= 0){
				core.getBackPanel().removeChild(backSelectionRect);
			}else{
				refreshBackSelectionRect();
			}
		}
		
		/**
		  Refreshes the position and size of the backSelectionRect
		*/
		private function refreshBackSelectionRect():void{
			var mselect:MovieClip 		= core.getMainSelectionRect();
			backSelectionRect.x 		= mselect.x;
			backSelectionRect.y 		= mselect.y;
			
			backSelectionRect.graphics.clear();
			backSelectionRect.graphics.beginFill(0xFFFFFF, 0);
			backSelectionRect.graphics.drawRect(
					-mselect.width/2-30,
					-mselect.height/2-30,
					 mselect.width+60,
					 mselect.height+60);
			backSelectionRect.graphics.endFill();
		}
		
		/**
		  Saves the blur displayed while moving mouse
		*/
		private function saveSelectedShapesBlur(evt:MouseEvent):void{
			// If there has been any effective blurring
			if(blurx != selectionBackup[1].x ||
				blury != selectionBackup[1].y){
				
				// We rotate all objects
				for(var i:uint = 0; i<core.getSelectedShapes().length; ++i){
					core.getSelectedShapes()[i].setBlur(selectionBackup[i+1].x, selectionBackup[i+1].y); // We restore the blurring as before
					core.blurShape(core.getSelectedShapes()[i], blurx, blury, true, // Save this action
							(i == 0) // First action of the cluster
						);
				}
				
				if(core.getSelectedShapes().length == 1 &&
				   core.getShapeShadow(core.getSelectedShapes()[0]) != null && // if it has shadow, then it was created before this frame
				   core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().x == core.getSelectedShapes()[0].getBlur().x &&
				   core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().y == core.getSelectedShapes()[0].getBlur().y){
					// Ok, if we get here is because THE only object we were blurring
					// we are putting it back to how it was before
					// So now we proceed invalidating all other blurring actions in this frame
					var array:Array = core.invalidateActions(Action.BLUR, core.getSelectedShapes()[0].getFullID());
					if(array != null){
						core.addAction(new Action(
							Action.INVALIDATE_PREV_ACTIONS,
							core.getSelectedShapes()[0].getFullID(),
							array), false
							);
					}
				}
			}
			blurx = 0;
			blury = 0;
			
			core.removeChild(editingLines);
			core.removeChild(tfield);
		}
		
		/**
		  Displays blur on selected shapes while mouse is moving
		*/
		private function selectedShapesBlur(evt:MouseEvent):void{
			var mselec:MovieClip = core.getMainSelectionRect();
			
			var nblurx:Number = Math.abs(Math.abs(evt.stageX - mselec.x)-Math.abs((selectionBackup[0] as Point).x - mselec.x))/10;
			var nblury:Number = Math.abs(Math.abs(evt.stageY - mselec.y)-Math.abs((selectionBackup[0] as Point).y - mselec.y))/10;
			
			// Make blurring exponential to the distance of the mouse
			nblurx = nblurx*nblurx;
			nblury = nblury*nblury;
			
			if(! firstEditing){
				firstEditing = true;
				core.addChild(editingLines);
				editingLines.x = mselec.x;
				editingLines.y = mselec.y;
				core.addChild(tfield);
			}
			
			// Make it easier to set blur to zero
			if(nblurx > 0 && nblurx < 1) nblurx = 0;
			if(nblury > 0 && nblury < 1) nblury = 0;
			// Fix a limit to blurring (it is absurd to blur more than the stage is able to show)
			if(nblurx > 300) nblurx = 300;
			if(nblury > 300) nblury = 300;
			
			if(core.getSelectedShapes().length == 1 &&
			   core.getShapeShadow(core.getSelectedShapes()[0]) != null){
				if(Math.abs(core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().x - nblurx) < 1){
					nblurx = core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().x;
				}
				if(Math.abs(core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().y - nblury) < 1){
					nblury = core.getShapeShadow(core.getSelectedShapes()[0]).getBlur().y;
				}
			}
			
			// If shift key is pressed, make the blurring square
			if(evt.shiftKey){
				if(nblurx > nblury) nblury = nblurx;
				else nblurx = nblury;
			}
			
			for(var i:uint = 0; i<core.getSelectedShapes().length; ++i){
				core.blurShape(core.getSelectedShapes()[i], nblurx, nblury);
			}
			
			blurx = nblurx;
			blury = nblury;
			
			// Background paintings to show lines and text
			tfield.text		= "("+String(Math.round(blurx))+"px, "+String(Math.round(blury))+"px)";
			tfield.x		= evt.stageX+15;
			tfield.y		= evt.stageY+17;
			
			editingLines.graphics.clear();
			editingLines.graphics.lineStyle(9.5, 0x77FF77, 0.2);
			//editingLines.graphics.drawCircle(0, 0, core.distanceOfNum(mselec, mselec.width/2 + mselec.x, mselec.height/2 + mselec.y));
			editingLines.graphics.lineStyle(Math.max((mselec.height/2)*0.1, (mselec.width/2)*0.1) , 0x77FF77, 0.3, false, "normal", flash.display.CapsStyle.NONE, flash.display.JointStyle.MITER);
			editingLines.graphics.drawRect(-mselec.width/2, -mselec.height/2, mselec.width, mselec.height);
		}
		
		/**
		  Hides the original cursor and shows the rotate one
		*/
		private function showBlurCursor(evt:MouseEvent):void{
			Mouse.hide();
			blurCursor.startDrag(true);
		}
		
		

		
	}
}